package org.demo.net.qsee;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import net.sourceforge.jpcap.capture.PacketListener;
import net.sourceforge.jpcap.net.Packet;
import net.sourceforge.jpcap.net.UDPPacket;

/**
 * 
 * @author  
 * @date    2010-11-7
 * @file    org.demo.net.qsee.UDPPacketListener.java
 */
public class UDPPacketListener implements PacketListener{
	private static int _counter = 0;
	// local ip
	private static String localhost = "127.0.0.1";
	// valid ips
	private Set<String> set_ips = new HashSet<String>();
	// captured qq
	private Map<Integer,String> map_qq = new HashMap<Integer,String>(); 
	/**
	 * 构造函数
	 */
	public UDPPacketListener(){
		URL url = this.getClass().getResource("ips.txt");
		BufferedReader buf = null;
		try {
			buf = new BufferedReader(new InputStreamReader(url.openStream()));
			String data = null;
			while ((data = buf.readLine()) != null){
				set_ips.add(data);
			}
			// initiate localhost ip
			localhost = InetAddress.getLocalHost().getHostAddress();
		} catch (Exception e) {
			System.out.println("Error : can't load ips.txt.");			
		} finally {
			try { if (buf != null) {buf.close();}} catch(Exception e){}
		}		
	}
	/**
	 * receive data packets
	 */
	@Override
	public void packetArrived(Packet packet) {
		if (!(packet instanceof UDPPacket)){
			return;
		}
		UDPPacket udp_packet = (UDPPacket)packet;
		String fromIp = udp_packet.getSourceAddress();
		String toIp = udp_packet.getDestinationAddress();
		if (set_ips.contains(fromIp)){
			analyzeFromQQ(udp_packet);
		} else if (set_ips.contains(toIp)){
			analyzeToQQ(udp_packet);
		} else if (!localhost.equals(fromIp) && !localhost.equals(toIp)){
			analyzeOther(udp_packet);
		}		
	}
	/**
	 * 分析由 qq server 发来的数据包
	 * @param udpPacket
	 */
	private void analyzeFromQQ(UDPPacket udpPacket) {
		_counter++;
		String from = udpPacket.getSourceAddress();
		String to = udpPacket.getDestinationAddress();
		try {
			byte[] data = udpPacket.getUDPData();			
			if (data.length >= 15){
				int fqq = 0x00;
				// 提取发送者 qq
				fqq = (0xFF & data[7]) << 8;
				fqq = ((0xFF & data[8]) | fqq) << 8;
				fqq = ((0xFF & data[9]) | fqq) << 8;
				fqq = (0xFF & data[10]) | fqq;				
				map_qq.put(fqq, to + "<-" + from);
				System.out.println(map_qq);
			}
		} catch(Exception e){
			
		}
	}
	/**
	 * 分析发往 qq server 的数据包
	 * @param udpPacket
	 */
	private void analyzeToQQ(UDPPacket udpPacket) {
		_counter++;
		String from = udpPacket.getSourceAddress();
		String to = udpPacket.getDestinationAddress();
		try {
			byte[] data = udpPacket.getUDPData();				
			if (data.length >= 15){
				int fqq = 0x00;
				// 提取发送者 qq
				fqq = (0xFF & data[7]) << 8;
				fqq = ((0xFF & data[8]) | fqq) << 8;
				fqq = ((0xFF & data[9]) | fqq) << 8;
				fqq = (0xFF & data[10]) | fqq;
				map_qq.put(fqq, from + "->" + to);
				System.out.println(map_qq);
			}
		} catch(Exception e){
			
		}
	}
	/**
	 * 分析其他数据包
	 * @param udpPacket
	 */
	private void analyzeOther(UDPPacket udpPacket) {
		_counter++;
		String from = udpPacket.getSourceAddress();
		String to = udpPacket.getDestinationAddress();		
		try {
			byte[] data = udpPacket.getUDPData();
			// is qq packet
			if (isQQPacket(data)){
				if (data.length >= 15){
					int fqq = 0x00;
					// 提取发送者 qq
					fqq = (0xFF & data[7]) << 8;
					fqq = ((0xFF & data[8]) | fqq) << 8;
					fqq = ((0xFF & data[9]) | fqq) << 8;
					fqq = (0xFF & data[10]) | fqq;
					map_qq.put(fqq, from + "->" + to);
					System.out.println(map_qq);
				}
			}
		} catch(Exception e){
			
		}
	}
	/**
	 * 是否为 qq 协议包
	 * @param data
	 * @return
	 */
	private boolean isQQPacket(byte[] data) {
		if (data[0] != 2){
			return false;
		}
		int last = data[data.length - 1];
		if (last == -37 || last == -12 || last == 3 || last == 17
				|| last == 87){
			return true;
		}
		return false;
	}
}
